#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "ethqos.h"
#include "evalsoc.h"
#include "arp.h"
#include "evalsoc_uart.h"
#include "dbg_cli.h"
#include "ipaddr.h"
#include "udp.h"
#include "eth.h"
#include "ipv4.h"



#pragma pack(push, 1)

#pragma pack(pop)

// 回复内容
static const char *reply_payload = "send udp data";
static const uint16_t reply_payload_len = 13;


/**
 * @brief 回复UDP请求
 * @param pctx 数据包的描述符结构体
 * @param pdat 请求数据包
 * @param tlen 待发送数据长度
 * @return 0 成功，其他失败
 */
int udp_make_reply(eqos_context_t *pctx, uint8_t *pdat, int tlen) {


    EthernetHeader *eth = (EthernetHeader*)pdat;
    IPv4Header *ip = (IPv4Header*)(pdat + sizeof(EthernetHeader));
    UDPHeader *udp = (UDPHeader*)(pdat + sizeof(EthernetHeader) + sizeof(IPv4Header));
    
    // 分配回复包内存
    void *reply_buf;
    if (fpa_alloc(&reply_buf) != 0) {
        printf("fpa_alloc failed\n");
        return -1;
    }
    memset(reply_buf, 0, 0x680); // 清空缓冲区

    // 构造以太网头部
    eth_make_reply(eth, reply_buf);
    // 构造IP头部（交换IP）
    ipv4_make_reply(ip, reply_buf,reply_payload_len);

    // 构造UDP头部（交换端口）
    UDPHeader *reply_udp = (UDPHeader*)(reply_buf + sizeof(EthernetHeader) + sizeof(IPv4Header));
    reply_udp->src_port = udp->dest_port;
    reply_udp->dest_port = udp->src_port;
    reply_udp->length = htons(sizeof(UDPHeader) + reply_payload_len);
    reply_udp->checksum = 0 ;  // 校验和计算

    // 填充回复内容
    memcpy(reply_udp->payload, reply_payload, reply_payload_len);

    // 发送回复包
    int pkt_len = sizeof(EthernetHeader) + sizeof(IPv4Header) + sizeof(UDPHeader) + reply_payload_len;
    int ret = dbg_eth_trans(pctx, reply_buf, pkt_len);

    debug_dump_hex( (uint8_t *)reply_buf, pkt_len );


    if (ret != 0) {
        printf("dbg_eth_trans failed\n");
        fpa_free(reply_buf);
        return -1;
    }

    return 0;
}

/**
 * @brief 发送UDP数据包
 * @param pctx 数据包的描述符结构体
 * @param dest_mac 目标MAC地址
 * @param dest_ip 目标IP地址
 * @param dest_port 目标端口号
 * @param src_port 源端口号
 * @param payload 负载数据
 * @param payload_len 负载长度
 * @return 0 成功，其他失败
 */
int udp_send_packet(eqos_context_t *pctx, const uint8_t *dest_mac, const uint8_t *dest_ip, 
    uint16_t dest_port, uint16_t src_port, const uint8_t *payload, uint16_t payload_len) {

    void *packet_buf;
    if (fpa_alloc(&packet_buf) != 0) {
        printf("Failed to allocate packet buffer\n");
        return -1;
    }
    memset(packet_buf, 0, 0x680); // 清空缓冲区

    // 构造以太网头部
    EthernetHeader *eth = (EthernetHeader *)packet_buf;
    memcpy(eth->dest_mac, dest_mac, 6);
    memcpy(eth->src_mac, DEV_MAC, 6);
    eth->ethertype = htons(0x0800); // IPv4

    // 构造IP头部
    IPv4Header *ip = (IPv4Header *)(packet_buf + sizeof(EthernetHeader));
    ip->ver_ihl = 0x45;          // IPv4 + 5 words
    ip->tos = 0;
    ip->total_length = htons(sizeof(IPv4Header) + sizeof(UDPHeader) + payload_len);
    ip->id = htons(0);           // 标识符
    ip->flags_frag_offset = 0;   // 不分片
    ip->ttl = 64;
    ip->protocol = 17;           // UDP
    memcpy(ip->src_ip, DEV_IP, 4);
    memcpy(ip->dest_ip, dest_ip, 4);

    

    //ip->checksum = ip_checksum(ip, sizeof(IPv4Header));

    // 构造UDP头部
    UDPHeader *udp = (UDPHeader *)(packet_buf + sizeof(EthernetHeader) + sizeof(IPv4Header));
    udp->src_port = htons(src_port);
    udp->dest_port = htons(dest_port);
    udp->length = htons(sizeof(UDPHeader) + payload_len);
    udp->checksum = 0;           //计算校验和

    // 填充负载数据
    memcpy(udp->payload, payload, payload_len);

    // 发送数据包
    int packet_len = sizeof(EthernetHeader) + sizeof(IPv4Header) + sizeof(UDPHeader) + payload_len;
    int ret = dbg_eth_trans(pctx, packet_buf, packet_len);
    if (ret != 0) {
        printf("Failed to send UDP packet\n");
        return -1;
    }

    return 0;
}


